import React, { useState, useEffect, useRef } from 'react';
import { MenuItem, TextField, Box } from '@mui/material';
import NetPyNEField from './NetPyNEField';
import SelectField from './Select';
import Utils from '../../utils/Utils';

interface CoordsRangeItem {
  value: string;
  label: string;
}

interface NetPyNECoordsRangeProps {
  id: string;
  name: string;
  model: string;
  conds?: string;
  items: CoordsRangeItem[];
  [key: string]: any;
}

/**
 * NetPyNECoordsRange Component
 * Component for selecting coordinate range type (absolute/normalized) and setting min/max values
 */
const NetPyNECoordsRange: React.FC<NetPyNECoordsRangeProps> = ({
  id,
  name,
  model,
  conds,
  items,
  ...otherProps
}) => {
  const [rangeType, setRangeType] = useState<string | undefined>(undefined);
  const [rangeValue, setRangeValue] = useState<[number | undefined, number | undefined]>([
    undefined,
    undefined,
  ]);
  const isMountedRef = useRef(true);

  useEffect(() => {
    isMountedRef.current = true;
    updateLayout();

    return () => {
      isMountedRef.current = false;
    };
  }, []);

  useEffect(() => {
    if (name) {
      updateLayout();
    }
  }, [name, conds]);

  const updateLayout = async (): Promise<void> => {
    const message = `netpyne_geppetto.${model}['${name}']${conds !== undefined ? `['${conds}']` : ''}`;
    const evalMessage = `[key in ${message} for key in ['${items[0].value}', '${items[1].value}']]`;

    try {
      const response = await Utils.evalPythonMessage(evalMessage, []);
      let newRangeType: string | undefined = undefined;

      if (response[0] && isMountedRef.current) {
        newRangeType = items[0].value;
      } else if (response[1] && isMountedRef.current) {
        newRangeType = items[1].value;
      }

      setRangeType(newRangeType);

      if (newRangeType) {
        const pythonMessage = `netpyne_geppetto.${model}['${name}']['${conds || ''}']['${newRangeType}']`;
        const rangeResponse = await Utils.evalPythonMessage(pythonMessage, []);
        if (rangeResponse && rangeResponse.length > 0) {
          setRangeValue(rangeResponse);
        }
      } else {
        setRangeValue([undefined, undefined]);
      }
    } catch (error) {
      console.error('Error updating layout:', error);
    }
  };

  const createMenuItems = (): React.ReactNode[] => {
    return items.map((obj) => (
      <MenuItem id={`${id + obj.label}MenuItem`} key={obj.value} value={obj.value}>
        {obj.label}
      </MenuItem>
    ));
  };

  const handleRangeTypeChange = (event: any, child: React.ReactNode): void => {
    const newRangeType = event.target.value as string;

    if (rangeType && rangeType.length > 0) {
      const pyPath = `netpyne_geppetto.${model}['${name}']['${conds || ''}']`;
      const startLetter = String(rangeType)[0];
      const pythonMessageDelOpposite = `${pyPath} = {k: v for k, v in ${pyPath}.items() if not k.startswith('${startLetter}')}`;
      Utils.execPythonMessage(pythonMessageDelOpposite);

      const currentRangeValue = rangeValue;
      if (!currentRangeValue.some((e) => e === undefined)) {
        const pythonMessage = `netpyne_geppetto.${model}['${name}']['${conds || ''}']['${newRangeType}'] = [${currentRangeValue}]`;
        Utils.execPythonMessage(pythonMessage);
      }
    }

    setRangeType(newRangeType);
  };

  const handleCoordParamChange = (index: number, newValue: string): void => {
    if (newValue === '' || /^\d+$/.test(newValue)) {
      if (rangeType && rangeType.length > 0) {
        const pyPath = `netpyne_geppetto.${model}['${name}']['${conds || ''}']`;
        const startLetter = String(rangeType)[0];
        const pythonMessageDelOpposite = `${pyPath} = {k: v for k, v in ${pyPath}.items() if not k.startswith('${startLetter}')}`;
        Utils.execPythonMessage(pythonMessageDelOpposite);
      }

      const newRangeValue: [number | undefined, number | undefined] = [...rangeValue];
      newRangeValue[index] = newValue === '' ? undefined : parseInt(newValue, 10);

      if (!newRangeValue.some((e) => e === undefined)) {
        const pythonMessage = `netpyne_geppetto.${model}['${name}']['${conds || ''}']['${rangeType}'] = [${newRangeValue}]`;
        Utils.execPythonMessage(pythonMessage);
      }

      setRangeValue(newRangeValue);
    }
  };

  const meta = conds !== undefined
    ? `${model}.${conds}.${items[0].value}`
    : `${model}.${items[0].value}`;
  const min = `${id}MinRange`;
  const max = `${id}MaxRange`;

  const minVal = rangeValue[0];
  const maxVal = rangeValue[1];

  return (
    <div>
      <NetPyNEField id={meta}>
        <SelectField
          id={`${id}Select`}
          label="Range type"
          value={rangeType || ''}
          onChange={handleRangeTypeChange}
        >
          {createMenuItems()}
        </SelectField>
      </NetPyNEField>
      {rangeType !== undefined ? (
        <Box width="100%" p={1}>
          <TextField
            type="number"
            label="Minimum"
            id={min}
            variant="filled"
            value={minVal ?? ''}
            fullWidth
            onChange={(e) => handleCoordParamChange(0, e.target.value)}
            sx={{ mb: 1 }}
          />
          <TextField
            type="number"
            label="Maximum"
            id={max}
            variant="filled"
            value={maxVal ?? ''}
            fullWidth
            onChange={(e) => handleCoordParamChange(1, e.target.value)}
          />
        </Box>
      ) : null}
    </div>
  );
};

export default NetPyNECoordsRange;

